package handler

import (
	"context"
	"fmt"
	"math"
	"net/http"
	"os"
	"pan/cache/redis"
	"pan/db"
	"pan/util"
	"path"
	"strconv"
	"strings"
	"time"
)

type MultiPartUploadInfo struct {
	FileHash   string
	FileSize   int
	UploadID   string
	ChunkSize  int
	ChunkCount int
}

// InitalChunkUploadHandler: 初始化文件分块上传
func InitalChunkUploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	username := r.Form.Get("username")
	fileHash := r.Form.Get("filehash")
	fileSize, err := strconv.Atoi(r.Form.Get("username"))
	if err != nil {
		w.Write(util.NewRespMsg(-1, "params invalid", nil).JSONBytes())
		return
	}
	rdb := redis.GetRedis()
	info := MultiPartUploadInfo{
		FileHash:   fileHash,
		FileSize:   fileSize,
		UploadID:   username + fmt.Sprintf("%x", time.Now().UnixNano()),
		ChunkSize:  5 * 1024 * 1024,
		ChunkCount: int(math.Ceil(float64(fileSize) / 5 * 1024 * 1024)),
	}
	err = rdb.HSet(
		context.Background(),
		"up_"+info.UploadID,
		"chunkcount", info.ChunkCount,
		"filehash", info.FileHash,
		"filesize", info.FileSize,
	).Err()
	if err != nil {
		w.Write(util.NewRespMsg(-1, "upload fail", nil).JSONBytes())
		return
	}
	w.Write(util.NewRespMsg(0, "ok", info).JSONBytes())
}

// ChunkHandler: 文件分块
func ChunkHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	// username := r.Form.Get("username")
	uploadID := r.Form.Get("uploadid")
	chunkIndex := r.Form.Get("index")
	rdb := redis.GetRedis()
	filePath := "data/" + uploadID + "/" + chunkIndex
	os.MkdirAll(path.Dir(filePath), 0744)
	fd, err := os.Create(filePath)
	if err != nil {
		w.Write(util.NewRespMsg(-1, "upload fail", nil).JSONBytes())
		return
	}
	defer fd.Close()
	buf := make([]byte, 1024*1024)
	for {
		n, err := r.Body.Read(buf)
		if err != nil {
			break
		}
		fd.Write(buf[:n])
	}
	err = rdb.HSet(
		context.Background(),
		"up_"+uploadID,
		"chunk_"+chunkIndex, 1,
	).Err()
	if err != nil {
		w.Write(util.NewRespMsg(-1, "upload fail", nil).JSONBytes())
		return
	}
	w.Write(util.NewRespMsg(0, "ok", nil).JSONBytes())
}

// CompleteUploadHandler: 上传完成通知
func CompleteUploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	username := r.Form.Get("username")
	uploadID := r.Form.Get("uploadid")
	fileHash := r.Form.Get("filehash")
	fileSize, _ := strconv.ParseInt(r.Form.Get("filesize"), 10, 64)
	fileName := r.Form.Get("filename")
	rdb := redis.GetRedis()
	val, err := rdb.HGetAll(
		context.Background(),
		"up_"+uploadID,
	).Result()
	if err != nil {
		w.Write(util.NewRespMsg(-1, "upload fail", nil).JSONBytes())
		return
	}
	fmt.Println(val)
	totalCount := 0
	chunkCount := 0
	for k, v := range val {
		if k == "chunkcount" {
			totalCount, _ = strconv.Atoi(v)
		} else if strings.HasPrefix(k, "chunk_") && v == "1" {
			chunkCount += 1
		}
	}
	if totalCount != chunkCount {
		w.Write(util.NewRespMsg(-2, "invalid request", nil).JSONBytes())
		return
	}
	db.OnFileUploadFinished(fileHash, fileName, "", fileSize)
	db.OnFileUploadFinished(username, fileName, "", fileSize)
	w.Write(util.NewRespMsg(0, "ok", nil).JSONBytes())
}
